package com.ms.game.db.util;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.persistence.Entity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.collection.PersistentList;

import com.ms.db.model.basic.ModelCfg;
import com.ms.game.db.DBCache;
import com.ms.game.db.exception.DBRuntimeException;
import com.xpec.c4.db.dao.HelperDAO;
import com.xpec.c4.db.dto.DTManualTransfer;
import com.xpec.c4.db.model.basic.BasicGameModel;

/**
 * 数据对象的工具类
 * 
 * @author Bany
 * 
 * @version 0.1
 */
public class Utility {

	private static final Log log = LogFactory.getLog(Utility.class);

	/**
	 * 给对象的指定字段赋值
	 * 
	 * @param field
	 *            字段
	 * @param obj
	 *            对象
	 * @param value
	 *            值
	 * @return 是否成功
	 */
	public static boolean setField(Object obj, Field field, Object value) {

		field.setAccessible(true);
		try {
			field.set(obj, value);
		} catch (IllegalArgumentException e) {
			log.error("cannot set field", e);
			throw e;
		} catch (IllegalAccessException e) {
			log.error("cannot set field", e);
			throw new DBRuntimeException(e);
		}

		return true;
	}

	/**
	 * 给对象的指定字段赋值
	 * 
	 * @param field
	 *            字段名称
	 * @param obj
	 *            对象
	 * @param value
	 *            值
	 * @return 是否成功
	 */
	public static boolean setField(Object obj, String field, Object value) {
		return setField(obj, getField(obj.getClass(), field), value);
	}

	/**
	 * 获得对象里指定字段的值
	 * 
	 * @param obj
	 *            对象
	 * @param fieldname
	 *            字段名称
	 * @return 值
	 */
	public static Object getField(Object obj, String fieldname) {
		Field field = getField(obj.getClass(), fieldname);
		if (field == null)
			return null;
		field.setAccessible(true);
		Object value = null;
		try {
			value = field.get(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}

	/**
	 * 获得对象里指定字段的值
	 * 
	 * @param obj
	 *            对象
	 * @param field
	 *            字段
	 * @return 值
	 */
	public static Object getField(Object obj, Field field) {
		if (field == null)
			return null;
		field.setAccessible(true);
		Object value = null;
		try {
			value = field.get(obj);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return value;
	}

	/**
	 * 获得给定对象的属性
	 * 
	 * @param c
	 *            类对象
	 * @param strField
	 *            属性名称
	 * @return 属性，如果未找到则返回 null
	 */
	public static Field getField(Class<?> c, String strField) {
		if (c == null)
			return null;

		Field field;
		int endIndex, beginIndex = 0;
		String fieldName = strField;
		endIndex = strField.indexOf('.');
		if (endIndex > 0) {
			fieldName = strField.substring(beginIndex, endIndex);
			beginIndex = endIndex + 1;
			field = getFieldFromSuperclass(c, fieldName);
			return field;
		} else {
			return getFieldFromSuperclass(c, fieldName);
		}
	}

	/**
	 * 根据类和字段，取出对应的字段。并把结果保存到缓存
	 * 
	 * @param c
	 *            类
	 * @param field
	 *            字段
	 * @return 对应的字段
	 */
	public static Field getFieldToDBCache(Class<?> c, Field field) {
		Field fieldCache = DBCache.getMappingField(field);
		if (fieldCache != null) {
			return fieldCache;
		}
		fieldCache = getField(c, field.getName());
		DBCache.setMappingField(field, fieldCache);
		DBCache.setMappingField(fieldCache, field);
		return fieldCache;
	}

	/**
	 * 根据类和字段，取出对应的字段。
	 * 
	 * @param c
	 *            类
	 * @param field
	 *            字段
	 * @return 对应的字段
	 */
	public static Field getField(Class<?> c, Field field) {
		Field fieldCache = getField(c, field.getName());
		return fieldCache;
	}

	/**
	 * 获得给定对象的属性，程序会递归的向上查找父类，直到找到给定名称的属性或到达继承树的根部
	 * 
	 * @param c
	 *            类对象
	 * @param strField
	 *            属性名称
	 * @return 属性，如果未找到则返回 null
	 */
	public static Field getFieldFromSuperclass(Class<?> c, String strField) {

		if (c == null)
			return null;

		try {
			int begin = strField.indexOf('[');
			if (begin > 0) {
				return c.getDeclaredField(strField.substring(0, begin));
			}
			return c.getDeclaredField(strField);
		} catch (NoSuchFieldException ex) {
			// ex.printStackTrace();

			return getField(c.getSuperclass(), strField);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 递归获取全部的字段属性<br>
	 * 包括父类和私有、保护、公开属性
	 * 
	 * @param c
	 *            类名
	 * @return 属性数组
	 */
	public static Field[] getAllFieldToCache(Class<?> c) {

		Field[] fieldCache = DBCache.getFields(c);
		if (fieldCache != null) {
			return fieldCache;
		}

		if (c == null)
			return new Field[0];

		Field[] fields, superFields, sumFields;
		superFields = getAllFieldToCache(c.getSuperclass());
		fields = c.getDeclaredFields();
		sumFields = new Field[superFields.length + fields.length];
		int i, j;
		for (i = 0; i < superFields.length; i++) {
			sumFields[i] = superFields[i];
		}
		for (j = 0; j < fields.length; j++) {
			Field field = fields[j];
			sumFields[i + j] = field;
		}

		DBCache.setFields(c, sumFields);

		return sumFields;
	}

	/**
	 * 递归获取全部的字段属性<br>
	 * 包括父类和私有、保护、公开属性
	 * 
	 * @param c
	 *            类名
	 * @return 属性数组
	 */
	public static Field[] getAllField(Class<?> c) {

		if (c == null)
			return new Field[0];

		Field[] fields, superFields, sumFields;
		superFields = getAllFieldToCache(c.getSuperclass());
		fields = c.getDeclaredFields();
		sumFields = new Field[superFields.length + fields.length];
		int i, j;
		for (i = 0; i < superFields.length; i++) {
			sumFields[i] = superFields[i];
		}
		for (j = 0; j < fields.length; j++) {
			Field field = fields[j];
			sumFields[i + j] = field;
		}

		return sumFields;
	}

	/**
	 * 对象属性拷贝的类
	 * 
	 * @param dest
	 *            源对象
	 * @param orig
	 *            目标对象
	 * @return 处理后的对象
	 */
	@SuppressWarnings("unchecked")
	public static Object copyProperties(Object orig, Object dest) {

		if (orig == null) {
			if (dest != null
					&& dest.getClass().getAnnotation(Entity.class) != null
					&& dest instanceof BasicGameModel
			) {
				HelperDAO.addDeleteEntity((BasicGameModel)dest);
			}
			return null;
		}
		if (dest == null) {
			return null;
		}
		Field[] fields = getAllFieldToCache(dest.getClass());
		Field origfield;
		for (Field destField : fields) {
			if (Modifier.isFinal(destField.getModifiers())) {
				continue;
			}
			// 手动拷贝，所以不自动拷贝
			if (destField.getAnnotation(DTManualTransfer.class) != null)
				continue;
			origfield = getFieldToDBCache(orig.getClass(), destField);
			if (origfield == null
					|| origfield.getAnnotation(DTManualTransfer.class) != null)
				continue;

			Object origValue = getField(orig, origfield);
			Object destValue = getField(dest, destField);

			if (origValue != null && !origValue.equals(destValue)) {
				if (origValue.getClass() == PersistentList.class) {
					
					List list = new ArrayList(((PersistentList) origValue));
//					List list = new Vector();
//					for (int i = 0; i < ((PersistentList) origValue).size(); i++) {
//						((List) list).add(((PersistentList) origValue).get(i));
//					}
					origValue = list;
				}
				setField(dest, destField, origValue);
			} else if (origValue == null) {
				setField(dest, destField, null);
			}

		}
		return dest;
	}

	public static void copyPropertiesForce(Object orig, Object dest) {
		if (orig == null) {
			log.error("copyPropertiesForce is error! orig is null! ");
			return ;
		}
		if (dest == null) {
			log.error("copyPropertiesForce is error! dest is null! ");
			return ;
		}
		Field[] destFields = getAllFieldToCache(dest.getClass());
		Field[] origFields = getAllFieldToCache(orig.getClass());
		
		HashMap<String, Field> origMap = new HashMap<String, Field>();
		
		for (Field field : origFields) {
			origMap.put(field.getName(), field);
		}
		
		Field origfield;
		for (Field destField : destFields) {
			if (Modifier.isFinal(destField.getModifiers())) {
				continue;
			}
			// 手动拷贝，所以不自动拷贝
			if (destField.getAnnotation(DTManualTransfer.class) != null)
				continue;
			origfield = origMap.get(destField.getName());
			if (origfield == null
					|| origfield.getAnnotation(DTManualTransfer.class) != null)
				continue;

			Object origValue = getField(orig, origfield);
			Object destValue = getField(dest, destField);

			if (origValue != null && !origValue.equals(destValue)) {
				if (origValue.getClass() == PersistentList.class) {
					
					List<?> list = new ArrayList(((PersistentList) origValue));
					origValue = list;
				}
				setField(dest, destField, origValue);
			} else if (origValue == null) {
				setField(dest, destField, null);
			}

		}
	}
	
	/**
	 * 从原类得到映射的MODE层类
	 * 
	 * @param orig
	 *            原类
	 * @return 映射的类
	 */
	@SuppressWarnings("unchecked")
	public static Class mapingClass(Class orig) {
		return ModelCfg.mappingClass.get(orig);
	}

	/**
	 * 从原类得到映射的MODE层类
	 * 
	 * @param orig
	 *            原类
	 * @return 映射的类
	 */
	@SuppressWarnings("unchecked")
	public static Object mappingObject(Object orig) {
		if (orig == null)
			return null;
		Class clazz = mapingClass(orig.getClass());
		if (clazz == null)
			return null;
		else {
			try {
				return clazz.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}

	}

}
